package com.zntech.app.common.instantcmd;

import static android.content.Context.BIND_AUTO_CREATE;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;


public class InstantCmdClient {
    private static final String TAG = InstantCmdClient.class.getSimpleName();
    private static final int MSG_SEND_TOUCH = 0x1;
    private static final int MSG_SEND_KEYCODE = 0x2;
    private static final int MSG_SEND_REGISTER_COMPONENT = 0x3;
    private static final int MSG_SEND_PASTE = 0x4;
    private static final int MSG_SEND_SCREENSHOT = 0x5;

    // Messenger
    private static final int INSTANT_CMD_SERVICE_MSG_TOUCH = 0xc0;
    private static final int INSTANT_CMD_SERVICE_MSG_KEYCODE = 0xc1;
    private static final int INSTANT_CMD_SERVICE_MSG_PASTE = 0xc2;
    private static final int INSTANT_CMD_SERVICE_MSG_SCREENSHOT = 0xc3;
    private static final int INSTANT_CMD_REGISTER_COMPONENT = 0xfc;

    private Context mApplicationContext;
    private Messenger mInstantCmdServiceMessenger;
    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private InstantCmdClient() {
        // 线程负责转发到IntantCmdService中处理
        mHandlerThread = new HandlerThread("instant_cmd_client", Process.THREAD_PRIORITY_FOREGROUND );
        mHandlerThread.start();
        Looper loop = mHandlerThread.getLooper();
        mHandler = new Handler(loop) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_SEND_TOUCH:
                        sendEvent(msg.getData(), INSTANT_CMD_SERVICE_MSG_TOUCH);
                        break;
                    case MSG_SEND_KEYCODE:
                        sendEvent(msg.getData(), INSTANT_CMD_SERVICE_MSG_KEYCODE);
                        break;
                    case MSG_SEND_REGISTER_COMPONENT:
                        sendEvent(msg.getData(), INSTANT_CMD_REGISTER_COMPONENT);
                        break;
                    case MSG_SEND_PASTE:
                        sendEvent(msg.getData(), INSTANT_CMD_SERVICE_MSG_PASTE);
                        break;
                    case MSG_SEND_SCREENSHOT:
                        sendEvent(msg.getData(), INSTANT_CMD_SERVICE_MSG_SCREENSHOT);
                        break;
                }
            }
        };
    }
    private static class InstantCmdHolder {
        private static InstantCmdClient mInstance = new InstantCmdClient();
    }

    static InstantCmdClient get(){
        return InstantCmdHolder.mInstance;
    }

    /**
     * @param applicationContext  need application context
     */
    void init(Context applicationContext){
        mApplicationContext = applicationContext;
        try {
            connectInstantCmdService();
        } catch (IllegalAccessException e) {
        }
    }

    void destroy(){
        if (mHandlerThread != null) {
            mHandlerThread.quit();
            mHandlerThread = null;
        }
    }

    private void connectInstantCmdService() throws IllegalAccessException {
        if (mApplicationContext == null) throw new IllegalAccessException();
        Intent intent = new Intent();
        intent.setAction("com.zntech.instant.cmd.InstantCmdService");
        intent.setPackage("com.haitang.app");
        mApplicationContext.bindService(intent, connection, BIND_AUTO_CREATE);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mInstantCmdServiceMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onInstantCmdServiceDisconnected");
        }
    };

    private void sendEvent(Bundle touchData, int msgId) {
        if (mInstantCmdServiceMessenger != null
                && mInstantCmdServiceMessenger.getBinder().isBinderAlive()) {
            Message message = Message.obtain(null, msgId);
            message.setData(touchData);
            try{
                mInstantCmdServiceMessenger.send(message);
            } catch (RemoteException e) {
                Log.d(TAG, "start restore instantcmd service: "+ e.getMessage());
                try {
                    connectInstantCmdService();
                } catch (IllegalAccessException illegalAccessException) {
                    Log.d(TAG, "connect instantcmd service error, context is null");
                }
            }
        }else {
            Log.d(TAG, "start restore instantcmd service ");
            try {
                connectInstantCmdService();
            } catch (IllegalAccessException e) {
                Log.d(TAG, "connect instantcmd service error, context is null");
            }
        }
    }

    void registerComponent(String intentAction) {
        Bundle bundle = new Bundle();
        bundle.putString("action", intentAction);
        Message msg = Message.obtain(mHandler, MSG_SEND_REGISTER_COMPONENT);
        msg.setData(bundle);
        mHandler.sendMessage(msg);
    }

    void touch(int event, float x, float y, int delayTime) {
        Bundle bundle = new Bundle();
        bundle.putFloat("x", x);
        bundle.putFloat("y", y);
        bundle.putInt("e", event);
        Message msg = Message.obtain(mHandler, MSG_SEND_TOUCH);
        msg.setData(bundle);
        mHandler.sendMessageDelayed(msg, delayTime);
    }

    /**
     * 暂时支持匀速滑动，10ms 一个点
     * @param startX
     * @param startY
     * @param endX
     * @param endY
     * @param duration
     */
    void slide(float startX, float startY, float endX, float endY, int duration) {

        touch(MotionEvent.ACTION_DOWN, startX, startY, 0);

        float xiDistance = endX - startX;
        float yiDistance = endY - startY;

        float xDelta = xiDistance / duration;
        float yDelta = yiDistance / duration;

        int cur = 0;
        while (cur < duration) {
            touch(MotionEvent.ACTION_MOVE,xDelta * cur + startX,yDelta * cur + startY, cur);
            cur += 10;
        }

        touch(MotionEvent.ACTION_UP, endX, endY, duration);
    }


    /**
     * 模拟 android.view.KeyEvent
     * 参考adb shell input keyevent
     * @param keycode
     * @param delayTime
     */
    void doKeycode(int keycode, int delayTime) {
        Bundle bundle = new Bundle();
        bundle.putInt("code", keycode);
        Message msg = Message.obtain(mHandler, MSG_SEND_KEYCODE);
        msg.setData(bundle);
        mHandler.sendMessageDelayed(msg, delayTime);
    }

    void doPaste(int delayTime){
        Bundle bundle = new Bundle();
        bundle.putString("txt", "");
        Message msg = Message.obtain(mHandler, MSG_SEND_PASTE);
        msg.setData(bundle);
        mHandler.sendMessageDelayed(msg, delayTime);
    }

    void doScreenshot(String filePath, int delayTime){
        Bundle bundle = new Bundle();
        bundle.putString("file", filePath);
        Message msg = Message.obtain(mHandler, MSG_SEND_SCREENSHOT);
        msg.setData(bundle);
        mHandler.sendMessageDelayed(msg, delayTime);
    }
}
